package com.wb.spring.boot.autoconfigure.core;

import org.springframework.web.client.RestTemplate;

import java.io.Serializable;
import java.net.HttpURLConnection;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author sw
 * @create 2023-03-06 11:23
 */
public final class Request implements Serializable {
    public enum HttpMethod {
        GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH
    }

    private final HttpMethod httpMethod;
    private final String url;
    private final Map<String, Collection<String>> headers;
    private final byte[] body;

    private final Map<String, Object> uriVariables;
    private final RestTemplate restTemplate;

    Request(HttpMethod method,
            String url,
            Map<String, Collection<String>> headers,
            byte[] body,
            Map<String, Object> uriVariables,
            RestTemplate restTemplate) {
        this.httpMethod = method;
        this.url = url;
        this.headers = headers;
        this.body = body;
        this.uriVariables = uriVariables;
        this.restTemplate = restTemplate;
    }

    public HttpMethod getHttpMethod() {
        return httpMethod;
    }

    public String getUrl() {
        return url;
    }

    public Map<String, Collection<String>> getHeaders() {
        return headers;
    }

    public byte[] getBody() {
        return body;
    }

    public Map<String, Object> getUriVariables() {
        return uriVariables;
    }

    public RestTemplate getRestTemplate() {
        return restTemplate;
    }


    public static class Options {

        private final long connectTimeout;
        private final TimeUnit connectTimeoutUnit;
        private final long readTimeout;
        private final TimeUnit readTimeoutUnit;
        private final boolean followRedirects;


        /**
         * Creates a new Options Instance.
         *
         * @param connectTimeout     value.
         * @param connectTimeoutUnit with the TimeUnit for the timeout value.
         * @param readTimeout        value.
         * @param readTimeoutUnit    with the TimeUnit for the timeout value.
         * @param followRedirects    if the request should follow 3xx redirections.
         */
        public Options(long connectTimeout, TimeUnit connectTimeoutUnit,
                       long readTimeout, TimeUnit readTimeoutUnit,
                       boolean followRedirects) {
            super();
            this.connectTimeout = connectTimeout;
            this.connectTimeoutUnit = connectTimeoutUnit;
            this.readTimeout = readTimeout;
            this.readTimeoutUnit = readTimeoutUnit;
            this.followRedirects = followRedirects;
        }


        /**
         * Creates the new Options instance using the following defaults:
         * <ul>
         * <li>Connect Timeout: 10 seconds</li>
         * <li>Read Timeout: 60 seconds</li>
         * <li>Follow all 3xx redirects</li>
         * </ul>
         */
        public Options() {
            this(10, TimeUnit.SECONDS, 60, TimeUnit.SECONDS, true);
        }

        /**
         * Defaults to 10 seconds. {@code 0} implies no timeout.
         *
         * @see java.net.HttpURLConnection#getConnectTimeout()
         */
        public int connectTimeoutMillis() {
            return (int) connectTimeoutUnit.toMillis(connectTimeout);
        }

        /**
         * Defaults to 60 seconds. {@code 0} implies no timeout.
         *
         * @see java.net.HttpURLConnection#getReadTimeout()
         */
        public int readTimeoutMillis() {
            return (int) readTimeoutUnit.toMillis(readTimeout);
        }


        /**
         * Defaults to true. {@code false} tells the client to not follow the redirections.
         *
         * @see HttpURLConnection#getFollowRedirects()
         */
        public boolean isFollowRedirects() {
            return followRedirects;
        }

        /**
         * Connect Timeout Value.
         *
         * @return current timeout value.
         */
        public long connectTimeout() {
            return connectTimeout;
        }

        /**
         * TimeUnit for the Connection Timeout value.
         *
         * @return TimeUnit
         */
        public TimeUnit connectTimeoutUnit() {
            return connectTimeoutUnit;
        }

        /**
         * Read Timeout value.
         *
         * @return current read timeout value.
         */
        public long readTimeout() {
            return readTimeout;
        }

        /**
         * TimeUnit for the Read Timeout value.
         *
         * @return TimeUnit
         */
        public TimeUnit readTimeoutUnit() {
            return readTimeoutUnit;
        }

    }

}
